package com.crtf.kotlin.maven.lombok.kotlin.controller

import com.crtf.kotlin.maven.lombok.kotlin.dto.FishDTO
import com.crtf.kotlin.maven.lombok.kotlin.dto.FishnetDTO
import com.crtf.kotlin.maven.lombok.kotlin.dto.ResultDTO
import com.crtf.kotlin.maven.lombok.kotlin.service.KotlinFishService
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.validation.BindException
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.*
import org.springframework.web.context.request.WebRequest
import java.lang.invoke.MethodHandles
import java.util.stream.Collectors

@RestController
@RequestMapping("/kotlin/fish")
class KotlinFishController {

    private val log :Logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass().name)

    @Autowired
    private lateinit var kotlinFishService: KotlinFishService

    @RequestMapping("/fishnet/{fishnetIndex:0}", method = [RequestMethod.GET], consumes = [MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE])
    fun queryFishnet(@PathVariable fishnetIndex: Int): ResultDTO<FishnetDTO<*>> {
        log.debug("fishnetIndex: $fishnetIndex")
        return ResultDTO of Result.success(kotlinFishService.queryFishnet(fishnetIndex))
    }


    @RequestMapping("/fishnet/{fishnetIndex:0}", method = [RequestMethod.PUT], consumes = [MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE])
    fun insertFish(@PathVariable fishnetIndex: Int, @RequestBody @Validated fish : FishDTO): ResultDTO<Boolean?> {
        log.debug("fishnetIndex: {}, fish: {}", fishnetIndex, fish)
        return ResultDTO of Result.success(kotlinFishService.insertFish(fishnetIndex, fish))
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = [Throwable::class])
    fun allExceptionHandler(ex: Exception, request: WebRequest): ResultDTO<Unit> {
        log.error("allExceptionHandler", ex)
        return ResultDTO.parse(Result.failure(ex), msgParse = { it.exceptionOrNull()?.message!!})
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = [BindException::class, MethodArgumentNotValidException::class])
    fun bindExceptionHandler(ex: Exception, request: WebRequest): ResultDTO<Unit> {
        log.error("allExceptionHandler", ex)
        return ResultDTO.parse(Result.failure(ex), msgParse = {
            if (it.exceptionOrNull() is BindException) {
                val bindException = it.exceptionOrNull() as BindException
                bindException.fieldErrors.stream()
                    .map { it2 -> "${it2.field}: ${it2.defaultMessage}" }
                    .collect(Collectors.joining("; "))
            } else if (it.exceptionOrNull() is MethodArgumentNotValidException) {
                val methodArgumentNotValidException = it.exceptionOrNull() as MethodArgumentNotValidException
                val bindingResult = methodArgumentNotValidException.bindingResult
                bindingResult.fieldErrors.stream()
                    .map { it2 -> "${it2.field}: ${it2.defaultMessage}" }
                    .collect(Collectors.joining("; "))
            } else ex.message
        })
    }

}